class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static distance(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        return Math.hypot(dx, dy);
    }
}

class MatchstickMen {
    constructor(canvasId) {
        this.canvasId = canvasId;
        this.selected = [];
        this.history = [];
        this.nodeName = ["head", "body", "hand", "elbow", "knee", "foot"];
        this.nodes = {};
        this.nodes.head = [new Point(0, -100)];
        this.nodes.body = [new Point(0, -50), new Point(0, 0), new Point(0, 50)];
        this.nodes.hand = [new Point(-50, 50), new Point(50, 50)];
        this.nodes.elbow = [new Point(-40, 0), new Point(40, 0)];
        this.nodes.knee = [new Point(-25, 100), new Point(25, 100)];
        this.nodes.foot = [new Point(-25, 175), new Point(25, 175)];
        this.property = {
            color: "red",
            headRadius: 30,
            headStroke: false,
            lineWidth: 10
        }
    }

    setCanvas(){
        return document.querySelector(this.canvasId).getContext("2d");
    }

    /**
     * 设置线形
     * @param width
     * @param cap
     * @param join
     */
    setLineStyle(width, cap, join){
        let context = this.setCanvas();
        context.lineWidth = width;
        let lineCap = ["butt", "round", "square"];
        context.lineCap = lineCap[cap];
        let lineJoin = ["bevel", "round", "miter"];
        context.lineJoin = lineJoin[join];
    }

    /**
     * 绘制园
     * @param center {Point}
     * @param radius {number}
     * @param color {string}
     * @param isStroke {boolean}
     */
    drawCircle(center, radius, color, isStroke){
        let context = this.setCanvas();
        context.beginPath();
        context.fillStyle = color;
        context.strokeStyle = color;
        context.arc(center.x, center.y, radius,0,2*Math.PI);
        isStroke ? context.stroke() : context.fill();
    }

    /**
     * 绘制折线
     * @param points {array}
     * @param lineCap {number}
     * @param lineJoin {number}
     * @param lineWidth {number}
     * @param color {string}
     */
    drawPolyline(points, lineCap, lineJoin, lineWidth, color){
        let context = this.setCanvas();
        this.setLineStyle(lineWidth, lineCap, lineJoin);
        context.strokeStyle = color;
        context.beginPath();
        context.moveTo(points[0].x, points[0].y);
        for (let i=1;i<points.length;i++){
            context.lineTo(points[i].x, points[i].y);
        }
        context.stroke();
    }

    drawMatchstickMen(nodes, headRadius, isHeadStroke, lineWidth, color){
        this.drawCircle(nodes.head[0], headRadius, color, isHeadStroke);
        this.drawPolyline(nodes.body, 1, 1, lineWidth, color);
        let arms = [nodes.hand[0], nodes.elbow[0],
            nodes.body[0], nodes.elbow[1], nodes.hand[1]];
        this.drawPolyline(arms, 1, 1, lineWidth, color);
        let legs = [nodes.foot[0], 0, nodes.knee[0],
            nodes.body[2], nodes.knee[1], nodes.foot[1]];
        this.drawPolyline(legs, 1, 1, lineWidth, color);
    }

    draw(){
        this.drawMatchstickMen(this.nodes, this.property.headRadius, this.property.headStroke,
            this.property.lineWidth, this.property.color);
    }

    /**
     * 选择节点
     * @param nameCount {number}
     * @param childCount {number}
     * @returns {*}
     */
    selectNode(nameCount, childCount){
        return this.nodes[this.nodeName[nameCount]][childCount];
    }

    /**
     * 返回当前选择的节点
     * @returns {*}
     */
    selectedNode(){
        return this.nodes[this.nodeName[this.selected[0]]][this.selected[1]];
    }

    /**
     * 检查点是否在某个节点的选择范围内
     * @param point
     * @param selectRadius
     * @returns {number}
     */
    getSelected(point, selectRadius){
        for (let nameCount=0; nameCount<this.nodeName.length; nameCount++){
            for (let childCount=0; childCount<this.nodes[this.nodeName[nameCount]].length; childCount++){
                if (Point.distance(this.selectNode(nameCount, childCount), point) < selectRadius){
                    this.selected = [nameCount, childCount];
                    return 1;
                }
            }
        }
        return 0;
    }

    setSelectedNode(point){
        this.selectedNode().x = point.x;
        this.selectedNode().y = point.y;
    }

    /**
     * 根据坐标绘制可能选中的节点
     * @param point {Point}
     * @param radius {number}
     * @param color {string}
     */
    drawSelectNode(point, radius, color){
        if (this.getSelected(point, radius)) {
            this.drawCircle(this.selectedNode(), radius, color, false);
        }
    }

    /**
     * 绘制当前选中的节点
     * @param radius {number}
     * @param color {string}
     */
    drawSelectedNode(radius, color){
        this.drawCircle(this.selectNode(this.selected[0], this.selected[1]), radius, color, false);
    }

    moveTo(offsetX, offsetY){
        for (let nameCount=0; nameCount<this.nodeName.length; nameCount++){
            for (let childCount=0; childCount<this.nodes[this.nodeName[nameCount]].length; childCount++){
                this.selected = [nameCount, childCount];
                this.selectedNode().x += offsetX;
                this.selectedNode().y += offsetY;
            }
        }
    }

    addToHistory(){
        this.history.push(this.nodes);
    }

    drawHistory(count){
        if (this.history.length > 0 && count < this.history.length) {
            this.nodes = this.history[count];
            this.draw();
            return 1;
        }else {
            return 0;
        }
    }
}

function getCursorPosition(canvas, event){
    const rect = canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;
    return new Point(x, y);
}

function setCanvas(container, canvas){
    canvas.width = container.width * 0.9;
    canvas.height = container.height * 0.7;
    canvas.style.left = container.width * 0.1 / 2 + "px";
    canvas.style.top = "10px";
}

const container = document.querySelector("#container").getBoundingClientRect();
const information = document.querySelector("#information");
const cvs = document.querySelector("#canvas");
setCanvas(container, cvs);
information.style.padding = container.width * 0.1 / 2 + "px";
const ctx = cvs.getContext("2d");

let redMen = new MatchstickMen("#canvas")
redMen.moveTo( cvs.width / 2, cvs.height / 2);
redMen.draw(90, false, 30, "red");


let mousedown = 0;
let selected = 0;
let currentSelectNode;

cvs.addEventListener("mousemove", (e) => {
    const cursor = getCursorPosition(cvs, e);

    setCanvas(container, cvs);

    redMen.draw(90, false, 30, "red");
    if (mousedown === 1 && selected === 1){
        redMen.drawSelectedNode(10, "blue");
        redMen.setSelectedNode(cursor);
    }else{
        redMen.drawSelectNode(cursor, 10, "blue");
    }
});


cvs.addEventListener("mousedown", (e)=>{
    const cursor = getCursorPosition(cvs, e);
    if (redMen.getSelected(cursor, 10) === 1){
        currentSelectNode = redMen.selected;
        selected = 1;
    }
    mousedown = 1;
})

cvs.addEventListener("mouseup", ()=>{
    mousedown = 0;
    selected = 0;
})

//================
let current_frame = 0;
let frames = [];

document.querySelector("#btn_save").addEventListener("click", function (){
    redMen.addToHistory();
    current_frame = redMen.history.length - 1;
    document.querySelector("#current_frame").innerHTML = current_frame;
});

document.querySelector("#btn_prev").addEventListener("click", function (){
    if (current_frame > 0){
        current_frame -= 1;
        redMen.drawHistory(current_frame, 90, false, 30, "red");
        document.querySelector("#current_frame").innerHTML = current_frame;
    }
});

document.querySelector("#btn_next").addEventListener("click", function (){
    if (current_frame => 0 && current_frame < redMen.history.length){
        current_frame += 1;
        redMen.drawHistory(current_frame, 90, false, 30, "red");
        document.querySelector("#current_frame").innerHTML = current_frame;
    }
});